package com.spica.platform.user.controller;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.spica.platform.base.model.*;
import com.spica.platform.base.resolver.LoginUser;
import com.spica.platform.common.constant.CommonConstant;
import com.spica.platform.common.utils.EntityUtil;
import com.spica.platform.common.utils.StringUtil;
import com.spica.platform.common.utils.TreeUtil;
import com.spica.platform.user.constants.SysMenuConstant;
import com.spica.platform.user.exception.SysMenuException;
import com.spica.platform.user.exception.SysMenuRtnCodEnum;
import com.spica.platform.user.service.ISysMenuService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.vavr.control.Try;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.web.bind.annotation.*;

import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

@Slf4j
@RestController
@Api(tags = SysMenuConstant.SYS_MENU_API)
@RequestMapping("/menus")
@SuppressWarnings("unchecked")
public class SysMenuController {
	@Autowired
	private ISysMenuService sysMenuService;

	/**
	 * 删除菜单
	 */
	@PostMapping( "/remove/{menuId}")
	@ApiOperation(value = SysMenuConstant.DELETE_SYS_MENU_BY_ID)
	public ResponseEntity removeMenuByMenuId(@PathVariable Long menuId) {
		Try.of(() -> sysMenuService.removeById(menuId))
				.onFailure(ex -> log.error(SysMenuRtnCodEnum.SYS_MENU_00001.getRtnMessage(), ex))
				.getOrElseThrow(item -> new SysMenuException(SysMenuRtnCodEnum.SYS_MENU_00001));
		return ResponseEntity.succeed(SysMenuRtnCodEnum.SYS_MENU_00002);

	}

	/**
	 * 获取当前角色下的菜单列表
	 */
	@GetMapping(value = "/roleId", params = "roleId")
	@ApiOperation(value = SysMenuConstant.FIND_SYS_MENU_BY_ROLE_ID)
	public ResponseEntity<List<SysMenu>> findMenusByRoleId(@RequestParam Long roleId) {
		Set<Long> roleIds = new HashSet<>();
		roleIds.add(roleId);
		// 获取该角色对应的菜单
		return ResponseEntity.succeed(sysMenuService.findSysMenuByRoleIds(roleIds));
	}

	/**
	 * 角色代码对应的菜单列表
	 * @param roleCodes 角色代码
	 * @return 菜单列表
	 */
	@GetMapping(value = "/roleCodes", params = "roleCodes")
	@ApiOperation(value = SysMenuConstant.FIND_MENU_BY_ROLE_CODES)
	//unless表示缓存的结果是否应该被排除在缓存之外。默认值为一个空字符串，表示不排除任何结果。这里是说,如果根据roleCodes查询的结果为null,则不缓存
	@Cacheable(value = "menu", key = "#roleCodes", unless = "#result == null")
	public List<SysMenu> findMenusByRoleCodes(@RequestParam String roleCodes) {
		List<SysMenu> responseEntity = null;
		if (StringUtil.isNotEmpty(roleCodes)) {
			Set<String> roleSet = Convert.toSet(String.class, roleCodes) ;
			responseEntity = sysMenuService.findSysMenuByRoleCodes(roleSet, CommonConstant.PERMISSION);
		}
		return responseEntity;
	}

	/**
	 * 给角色分配菜单
	 * @param sysMenu 菜单
	 */
	@ApiOperation(value = SysMenuConstant.SET_MENU_TO_ROLE)
	@PostMapping("/granted")
	public ResponseEntity setMenuToRole(@RequestBody SysMenu sysMenu) {
		Try.of(() -> sysMenuService.setMenuToRole(sysMenu.getRoleId(), sysMenu.getMenuIds()))
				.onFailure(ex -> log.error(SysMenuRtnCodEnum.SYS_MENU_00003.getRtnCode(), ex))
				.getOrElseThrow(item -> new SysMenuException(SysMenuRtnCodEnum.SYS_MENU_00003));
		return ResponseEntity.succeed(SysMenuRtnCodEnum.SYS_MENU_00004);

	}

	/**
	 * 查询所有菜单
	 * @return 菜单列表
	 */
	@ApiOperation(value = SysMenuConstant.FIND_ALL_LIST)
	@GetMapping("/findAlls")
	public PageResult<SysMenu> findAlls() {
		List<SysMenu> list = sysMenuService.list(Wrappers.<SysMenu>lambdaQuery().orderByAsc(SysMenu::getSort));
		return PageResult.<SysMenu>builder().data(list).rtnCod(0).count((long) list.size()).build();
	}

	/**
	 * 查询所有一级菜单
	 * @return 一级菜单列表
	 */
	@ApiOperation(value = SysMenuConstant.FIND_ALL_MENU_ONE_LIST)
	@GetMapping("/findOnes")
	public PageResult<SysMenu> findOnes() {
		List<SysMenu> list = sysMenuService.findOnes();
		return PageResult.<SysMenu>builder().data(list).rtnCod(0).count((long) list.size()).build();
	}

	/**
	 * 新增菜单
	 * @param menu 菜单
	 * @return 是否新增成功
	 */
	@ApiOperation(value = SysMenuConstant.SAVE_OR_UPDATE_MENU)
	@PostMapping("saveOrUpdate")
	public ResponseEntity saveOrUpdate(@RequestBody SysMenu menu) {
		Try.of(() -> sysMenuService.saveOrUpdate(menu))
				.onFailure(ex -> log.error(SysMenuRtnCodEnum.SYS_MENU_00005.getRtnCode(), ex))
				.getOrElseThrow(item -> new SysMenuException(SysMenuRtnCodEnum.SYS_MENU_00005));
		return ResponseEntity.succeed(SysMenuRtnCodEnum.SYS_MENU_00006);
	}

	/**
	 * 查询当前用户菜单
	 * @param user 当前用户
	 * @return 当前用户菜单
	 */
	@GetMapping("/current")
	@ApiOperation(value = SysMenuConstant.FIND_CURRENT_USER_MENU)
	public ResponseEntity<List<SysMenu>> findMyMenu(@LoginUser SysUser user) {
		List<SysRole> roles = user.getRoles();
		if (CollectionUtil.isEmpty(roles)) {
			return ResponseEntity.succeed(Collections.emptyList());
		}
		List<SysMenu> menus = sysMenuService
				.findSysMenuByRoleCodes(EntityUtil.toSet(roles, SysRole::getCode), CommonConstant.MENU);
		
		return  ResponseEntity.succeed(TreeUtil.listToTree(menus, SysMenu::setSubMenus ,  SysMenu::getId,
				SysMenu::getParentId, (node) ->  ObjectUtil.equal(-1L, node.getParentId())));
	}
}
